<?php

class RegenExt {
	const CLASSTYPE_NORMAL = 'normal';
	const CLASSTYPE_ABSTRACT = 'abstract';
	const CLASSTYPE_FINAL = 'final';
	
	protected static $excludedPatterns = array(
		'/^ext\/.*/',
		'/^qore.php$/',
		'/^QoreBase\.php$/',
		'/^AutoLoader\.php$/',
	);
	
	public function getPath() {
		return dirname(__FILE__).DIRECTORY_SEPARATOR.'..'.DIRECTORY_SEPARATOR.'framework'.DIRECTORY_SEPARATOR;
	}
	
	public function run() {
		$path = $this->getPath();
		$extPath = $path.'ext'.DIRECTORY_SEPARATOR;
		
		foreach ($this->listDirRecur($path) as $file) {
			$fileName = substr($file, strlen($path)+1);
			$fileExtension = substr($fileName, -3);
			
			// filter non .php and excluded files
			if ($fileExtension != 'php') continue;
			foreach (static::$excludedPatterns as $pattern) {
				if (preg_match($pattern, $fileName)) continue 2;
			}
			
			$content = $this->getClassFileContents(
				$namespace = $this->getNamespace($fileName),
				$classname = $this->getClassname($fileName),
				$classtype = $this->getClassType($file)
			);
			$extFileName = $extPath.$fileName;
			
			@mkdir(dirname($extFileName), 0777, true);
			file_put_contents($extFileName, $content);
			echo "Created {$classtype} class definition for $namespace\\$classname in $fileName\n";
		}
	}
	
	protected function getClassFileContents($namespace, $classname, $classtype) {
		$classDefinition = $classtype == static::CLASSTYPE_NORMAL ? null : "$classtype ";
		
		return <<<PHP
<?php
/* This is an automated generated file */
/* DO NOT TOUCH */

namespace qore\\$namespace;

{$classDefinition}class $classname extends \\qore_base\\$namespace\\$classname {}
PHP;
	}
	
	protected function getNamespace($fileName) {
		return str_replace(DIRECTORY_SEPARATOR, "\\", dirname($fileName));
	}
	
	protected function getClassname($fileName) {
		return substr(basename($fileName), 0, -4);
	}
	
	protected function getClassType($file) {
		$type = static::CLASSTYPE_NORMAL;
		$tokens = token_get_all(file_get_contents($file));
		
		foreach ($tokens as $token) {
			// skip non-array tokens
			if (!is_array($token)) continue;
			
			$tokenValue = $token[0];
			
			if ($tokenValue == T_ABSTRACT) $type = static::CLASSTYPE_ABSTRACT;
			if ($tokenValue == T_FINAL) $type = static::CLASSTYPE_FINAL;
			if ($tokenValue == T_CLASS) return $type;
		}
		
		return $type;
	}
	
	protected function listDirRecur($path) {
	    // Directories to ignore when listing output. Many hosts
	    // will deny PHP access to the cgi-bin.
	    $ignore = array('cgi-bin', '.', '..');
		
	    $dh = @opendir($path);
		$files = array();
		
		if (!$dh) return $files;
		
	    while ($file = readdir($dh)) {
	        if (!in_array($file, $ignore)) {
				$filepath = "$path/$file";
				if (is_dir($filepath)) 
					$files = array_merge($files, static::listDirRecur($filepath));
				else
					$files[] = $filepath;
	        }
	    }
	    
	    closedir($dh);
		
		return $files;
	}
}

$tool = new RegenExt();
echo $tool->run();
